﻿using FySystem.Data.OrmA.Db;
using FySystem.Data.OrmA.Formatter;
using FySystem.IO;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
using System.Text;
using System.Text.Json;

namespace FySystem.Data.OrmA.Reflection
{
    /// <summary>
    /// 将数据库中的数据拷贝到实体
    /// </summary>
    class DataCopy
    {
        /// <summary>
        /// 查询数据并创建单个实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="reflectionInfo"></param>
        /// <param name="dbHelper"></param>
        /// <param name="formatResult"></param>
        /// <returns></returns>
        internal static T CopyDataToSingle<T>(ReflectionInfo reflectionInfo, DBHelper dbHelper, FormatResult formatResult)
        {
            try
            {
                using (DbCommand command = dbHelper.CreateDbCommand(formatResult, CommandType.Text))
                {
                    using (DbDataReader dr = command.ExecuteReader())
                    {
                        if (dr.Read())
                            return SetModelValue<T>(reflectionInfo, dr);
                        else
                            return default(T);
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 查询数据并创建单个CSon实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dbHelper"></param>
        /// <param name="fmtSQL"></param>
        /// <returns></returns>
        internal static CSon CopyDataToSingleC(DBHelper dbHelper, FormatResult formatResult)
        {
            try
            {
                using (DbCommand command = dbHelper.CreateDbCommand(formatResult, CommandType.Text))
                {
                    using (DbDataReader dr = command.ExecuteReader())
                    {
                        if (dr.Read())
                            return SetCSonValue(dr);
                        else
                            return null;
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 查询数据并创建实体列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="reflectionInfo"></param>
        /// <param name="dbHelper"></param>
        /// <param name="fmtSQL"></param>
        /// <returns></returns>
        internal static List<T> CopyDataToList<T>(ReflectionInfo reflectionInfo, DBHelper dbHelper, FormatResult fmtSQL)
        {
            List<T> res = null;
            try
            {
                using(DbCommand command = dbHelper.CreateDbCommand(fmtSQL, CommandType.Text))
                {
                    using(DbDataReader dr = command.ExecuteReader())
                    {
                        while (dr.Read())
                        {
                            T item = SetModelValue<T>(reflectionInfo, dr);
                            if (item != null)
                            {
                                res = res == null ? new List<T>() : res;
                                res.Add(item);
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 查询数据并创建CSon列表
        /// </summary>
        /// <param name="dbHelper"></param>
        /// <param name="fmtSQL"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        internal static List<CSon> CopyDataToListC(DBHelper dbHelper, FormatResult fmtSQL)
        {
            List<CSon> res = null;
            try
            {
                using (DbCommand command = dbHelper.CreateDbCommand(fmtSQL, CommandType.Text))
                {
                    using (DbDataReader dr = command.ExecuteReader())
                    {
                        while (dr.Read())
                        {
                            CSon item = SetCSonValue(dr);
                            res = res == null ? new List<CSon>() : res;
                            res.Add(item);
                        }
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 根据数据库数据创建实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataReader"></param>
        /// <returns></returns>
        internal static T SetModelValue<T>(ReflectionInfo reflectionInfo, IDataReader dataReader)
        {
            T res = Activator.CreateInstance<T>();
            try
            {
                for(int i = 0; i < dataReader.FieldCount; i++)
                {
                    string fieldName = dataReader.GetName(i).ToUpper();
                    if (reflectionInfo.Mapping.ContainsKey(fieldName))
                    {
                        ColumnProperty columnProperty = reflectionInfo.Mapping[fieldName];
                        PropertyInfo property = columnProperty.PropertyInfo;

                        //数组的暂时搞不定，忽略掉
                        if (property.PropertyType.Name.Contains("[]") == true)
                            continue;

                        object value = dataReader[i];
                        if (value == null)
                            continue;

                        switch (columnProperty.Column.DbFieldType)
                        {
                            case Attributes.DbFieldTypes.Json:
                                if (!string.IsNullOrWhiteSpace(value.ToString()))
                                    value = JsonSerializer.Deserialize(value.ToString(), columnProperty.PropertyInfo.PropertyType);
                                break;
                        }

                        SetPropertyValue(res, property, value);
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 根据数据库数据创建CSon
        /// </summary>
        /// <param name="reflectionInfo"></param>
        /// <param name="dataReader"></param>
        /// <returns></returns>
        private static CSon SetCSonValue(DbDataReader dataReader)
        {
            CSon res = new CSon(CSon.CSonTypes.CObject);
            try
            {
                for (int i = 0; i < dataReader.FieldCount; i++)
                {
                    string fieldName = dataReader.GetName(i);
                    object value = dataReader[i];

                    if (value == null)
                        res.Add(fieldName, CSon.CSonValueNull);
                    else if (value.Equals(DBNull.Value))
                        res.Add(fieldName, CSon.CSonValueNull);
                    else
                        res.Add(fieldName, CSon.ToCSon(value));
                }
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 设置属性值
        /// </summary>
        /// <param name="propertyInfo"></param>
        /// <param name="value"></param>
        internal static void SetPropertyValue(object model, PropertyInfo propertyInfo,object value)
        {
            try
            {
                if (value is DBNull)
                    return;

                Type proType = Nullable.GetUnderlyingType(propertyInfo.PropertyType);
                if (proType != null)
                    propertyInfo.SetValue(model, Convert.ChangeType(value, proType), null);
                else
                    propertyInfo.SetValue(model, Convert.ChangeType(value, propertyInfo.PropertyType), null);
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取实体属性的值
        /// </summary>
        /// <param name="propertyInfo"></param>
        /// <returns></returns>
        internal static object GetModelPropertyValue(PropertyInfo propertyInfo, object model)
        {
            try
            {
                if (propertyInfo == null || model == null)
                    return null;

                return propertyInfo.GetValue(model);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
